
#include "packet-info.h"
#include "packet-pool.h"
#include <stdlib.h>
#include <iostream>
using namespace std;


PacketInfo::PacketInfo() {
    // pkt_info_table_ = NULL;
}

PacketInfo::~PacketInfo() {
    list<pkt_info_t>::iterator it = pkt_info_table_.begin();
    for(; it != pkt_info_table_.end(); ++ it) {
	it->pkt_ids.clear();
	pkt_info_table_.erase(it);
    }
    // packet_info_t* current;
    // packet_info_t* temp;
    // HASH_ITER(hh, pkt_info_table_, current, temp) {
    // 	HASH_DEL(pkt_info_table_, current);
    // 	free(current);
    // }
}


// There should be some problems!!!
void PacketInfo::update_pkt_info(hdr_report_t report, int nodeid, int id) {
    bool new_prob;
    int seq_num = report.last_pkt_ - BITMAP_SIZE;
    nsaddr_t src_ip = report.src_ip_;
    int pktid;
    u_int16_t seq_temp;
    nsaddr_t src_temp;
 
    for (int i = 0; i <= BITMAP_SIZE; i++) {
      if(seq_num >= 1) {
	pktid = 0;
	src_temp = src_ip;
	seq_temp = seq_num;
	HASH_JEN_MIX(src_temp, seq_temp, pktid);
	if(seq_num == report.last_pkt_)
	  new_prob = true;
	else
	  new_prob = (bool)(report.bit_map_ & 0x80)/*1000 0000*/;

	if(new_prob == true) {
	    update_pkt_info(pktid, nodeid);
	}
      }
	  
      report.bit_map_ <<= 1;
      seq_num ++;
    }
}

/*
 * if p is a native packet, set previous hop's prob of p to true
 * if p is an encoded packet, all encoded packet info for previous 
 *    hop should be true
 * while this updating for packet info should not cause updating probguess,
 * probguess is only updated when receive a state report
 */
void PacketInfo::update_pkt_info(Packet * p, int prev_hop) {
    if(HDR_COPE(p)->encoded_num_ == 0) { //Native Packet
	update_pkt_info(HDR_CMN(p)->cope_pkt_id(), prev_hop);
    } else { //Encoded Packet
	for(int i = 0; i < HDR_COPE(p)->encoded_num_; i ++) {
	    update_pkt_info(HDR_COPE(p)->xoreds_[i].pkt_id_, prev_hop);
	}
    }
}

void PacketInfo::update_pkt_info(int pktid, int nodeid) {
    // packet_info_t* old_info = find_pkt_info(pktid, nodeid);    
    // if(old_info == NULL) 
    // 	add_pkt_info(pktid, nodeid, prob);
    // else
    // 	up_pkt_info(old_info, prob);

    list<pkt_info_t>::iterator it = pkt_info_table_.begin();
    for(; it != pkt_info_table_.end(); ++ it) {
	if(it->nodeid == nodeid) {
	    it->pkt_ids.insert(pktid);
	    return;
	}
    }

    pkt_info_t info;
    info.nodeid = nodeid;
    info.pkt_ids.insert(pktid);
    pkt_info_table_.push_back(info);
}

/* get probability of a specific neighbor and pkt_id */
bool PacketInfo::get_prob(int nb, int pkt_id) {
    // packet_info_t * pkt_info = find_pkt_info(pkt_id, nb);
    // if(pkt_info != NULL) {
    // 	return pkt_info->prob;
    // } else {
    // 	return false;
    // }

    list<pkt_info_t>::iterator it = pkt_info_table_.begin();
    for(; it != pkt_info_table_.end(); ++ it) {
	if(it->nodeid == nb) {
	    if(it->pkt_ids.find(pkt_id) != it->pkt_ids.end())
		return true;
	    else
		return false;
	}
    }
    return false;
}


/* return the number of packets from start_seq to last_seq */
int PacketInfo::get_pkt_count(int nb, 
			      nsaddr_t src_ip, 
			      uint16_t start_seq_num, 
			      uint16_t last_seq_num) {
    u_int16_t seq_iter = start_seq_num;
    int pkt_id;
    int count = 0;
    u_int16_t index;
    nsaddr_t src;
    for( ; seq_iter <= last_seq_num; seq_iter++) {
	if((int)seq_iter < 1)
	    continue;
	
	pkt_id = 0;
	src = src_ip;
	index = seq_iter;
	HASH_JEN_MIX(src, index, pkt_id);
	if(get_prob(nb, pkt_id) == true){
	    count++;
	}
    }
    return count;
}
